home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************************
- * SORT.C - An array of functions to sort data.
- *
- * VERSION 1.0 3/21/92
- * Version 1.1 8/2/92 Change fill to use FF vs. 0 to handle null strings
- * Version 1.2 10/29/92 Changed to put sort tag into accessible field
- * when fetching records. 'fetchtag'
- * Version 1.3 4/7/93 Changed to use Temporary Files to allow
- * multi-user activity with no clashes.
- ***********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <io.h>
- #include <sys\stat.h>
- #include <alloc.h>
-
- /** DEFINITIONS **/
-
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
-
- #define SMMAX 51200 /* bytes to ask for to sort */
- #define SMMIN 10240 /* Minimum bytes acceptable */
-
- #define STAGMAXLEN 80 /* Maximum Sort Tag Allowed */
-
- #define SORTOK 0 /* Sort Status is O.K. - No error */
- #define OK 0
- #define FETCHEND -1 /* End of Fetch */
- #define SORTERR -2 /* Sort Error */
-
-
-
- /****** -------- SORT ERROR CODES ------------ ******
-
- ERROR codes are found in the Global Variable sorterror
-
- 1 = InitSort failed - Not enough memory
- 2 = Unable to Open/Create Sort File
- 3 = ERROR Writing to Sort File
- 4 = Unable to Open/Create Merge File
- 5 = Not enough memory for Merge
- 6 = Error reading Sort Tag for Merge
- 7 = Error Writing to Merge File
- 8 = Error Reading Fetch File
- 9 = Sort Tag Length Exceeds Maximum
-
- *****************************************************/
-
-
- initsort(int taglength);
- void endsort();
- sort(char *ss, long srpos);
- initfetch();
- long fetch();
- fbread(unsigned rsize);
- sbwrite();
- merge();
- mbwrite(unsigned tagcount);
- bktfill(int bnum);
- zerobuf(char *bptr, unsigned count);
-
-
- /****************************************************************
- ** GLOBAL VARIABLES - Accessible in applications
- ****************************************************************/
- int sorterror; /* Contains Sort Error Code when Error */
- char fetchtag[STAGMAXLEN+1]; /* Area for Tag */
-
- /******************************************************
- * THE FOLLOWING VARIABLES ARE NOT FOR EXTERNAL ACCESS
- ******************************************************/
- char sortfile[81]; /* Temporary File Name */
- char mergefile[81]; /* Temporary File Name */
-
- int staglen; /* Length of ASCII Sort Tag */
- char *sbuf; /* sort Buffer Pointer */
- size_t sbsize; /* size of the Sort Buffer */
- unsigned bufmax; /* Max Number of tags that will fit into sort buffer */
- unsigned mbufmax; /* Max Tags fitting into merge buffer */
- long sortcount; /* Number of tags sorted */
- long fetchcount; /* Count of tags fetched */
- int sblocks; /* Number of sort blocks */
- unsigned bufcount; /* count of items in buffer */
-
- int mfh; /* Merge file Handle */
- int sfh; /* Sort File Handle */
- int sbfflag; /* Sort Buffer file flag */
- long sbfptr; /* Sort File Pointer */
- char *stptr; /* Sort Tag Pointer */
- long *lptr; /* Pointer to Long */
- unsigned *uptr; /* Pointer to Unsigned */
-
- long fetch(); /* Fetch returns a long value */
- size_t fbsize; /* Size of a Fetch Buffer */
-
- int tpsize = sizeof(long); /* Get the size of a tag pointer */
- int mcountsize = sizeof(unsigned); /* Size of the merge counter value */
- int tagsize; /* Size of a sort/merge tag (tag+pointer) */
- size_t bktsize; /* Size of the bucket in total */
-
- char *bktptr; /* Pointer into the merge buckets */
- int buckets; /* Number of Merge buckets (one for each sort block) */
- char *mrgbuf; /* Merge buffer start address */
- char *mbptr; /* Merge buffer pointer */
- size_t mbsize; /* Merge buffer size */
-
- /***************************************************************
- * INITSORT - Initialize the Sort
- ***************************************************************/
- initsort(int taglength)
- {
- if(taglength > STAGMAXLEN)
- {
- sorterror = 9; /* Indicate Tag size too big */
- return(SORTERR);
- }
- sorterror = 1; /* Init Sort Error */
- staglen = taglength; /* Set the Sort Tag Size */
- if(sbuf) free(sbuf); /* Free any existing buffer */
- sbsize = SMMAX; /* Go for maximum memory */
- while(sbsize > SMMIN)
- {
- sbuf=malloc(sbsize);
- if(sbuf) break; /* Leave loop when allocated */
- sbsize -= 2048; /* Reduce our attempt */
- }
- if(!sbuf) return(SORTERR); /* No Sort Space */
- zerobuf(sbuf,sbsize); /* Zero the sort buffer */
- stptr = sbuf; /* Point to the sort buffer */
- sortcount=0;
- bufcount=0;
- sblocks = 0;
- mfh = NULL;
- sbfflag = FALSE;
- tagsize = staglen + tpsize; /* Size of a sort/merge tag (tag+pointer) */
- bufmax = sbsize / tagsize; /* See how many will fit */
- return(SORTOK);
- }
-
-
- /******************************************************************
- * ENDSORT - End a sort function
- ******************************************************************/
- void endsort()
- {
- free(sbuf);
- sbuf = NULL;
- sbsize=0;
- sortcount=0;
- if(sfh!=NULL)
- {
- close(sfh); /* close the Sort Blocks file */
- remove(sortfile); /* Delete the Sort Blocks File */
- }
- if(mfh!=NULL)
- {
- close(mfh); /* close the Sort Blocks file */
- remove(mergefile); /* Delete the Sort Blocks File */
- }
- }
-
- /*******************************************************************
- * SORT - Accept a tag and sort it
- * If a tag exceeds the max sort tag length it will be truncated
- *******************************************************************/
- sort(char *ss, long srpos)
- {
- strcpy(stptr, ss); /* Copy in the Sort Tag */
- stptr += staglen; /* Move the Pointer */
-
- lptr = (long *) stptr; /* Set pointer to accept long value */
- *lptr = srpos;
-
-
- stptr += tpsize; /* Move pointer */
- sortcount++;
- bufcount++;
- if(bufcount >= bufmax) /* Write out the Sort Buffer, it's full */
- {
- if(sbwrite()!=SORTOK) return(SORTERR);
- stptr=sbuf; /* Reset the pointer */
- bufcount=0;
- }
- return(SORTOK);
- }
-
- /********************************************************************
- * INITFETCH - Initialize the fetch
- ********************************************************************/
- initfetch()
- {
- fbsize = bufmax * tagsize; /* Size of Fetch Buffer Reads */
- if(mfh != NULL)
- {
- sorterror = 9;
- if(lseek(mfh,0L,0)==-1L) return(SORTERR); /* Rewind Merge File for Fetch */
- if(fbread((unsigned)fbsize)!=SORTOK) return(SORTERR);
- }
- stptr=sbuf;
- fetchcount=0;
- bufcount=0;
- if(sfh!=NULL)
- {
- close(sfh); /* close the Sort Blocks file */
- remove(sortfile); /* Delete the Sort Blocks File */
- }
- return(SORTOK);
- }
-
- /**********************************************************************
- * FETCH - Fetch the next sorted record's pointer
- **********************************************************************/
- long fetch()
- {
- long srpos;
-
- if(fetchcount==sortcount) return(FETCHEND);
- strcpy(fetchtag, stptr); /* Copy the Fetch Tag for User */
- stptr += staglen;
- lptr = (long *) stptr;
- srpos=*lptr;
- stptr += tpsize; /* Move pointer */
- fetchcount++;
- bufcount++;
- if(bufcount >= bufmax)
- {
- if(fbread((unsigned) fbsize)!=SORTOK) return(SORTERR);
- stptr=sbuf;
- bufcount=0;
- }
- return(srpos);
- }
-
- /**********************************************************************
- * FBREAD - Read in a new portion of fetch tags into the buffer.
- **********************************************************************/
- fbread(unsigned rsize)
- {
- zerobuf(sbuf,sbsize); /* Zero the Buffer 1st */
- sorterror = 8;
- if(read(mfh,sbuf,rsize)==-1l) return(SORTERR);
- return(SORTOK);
- }
-
- /***********************************************************************
- * SBWRITE - Write out a sort buffer full of tags
- * Tags are written to a section of the sortfile.
- *
- ***********************************************************************/
- sbwrite()
- {
- char *sfname;
-
- if(!sbfflag)
- {
- sorterror = 2;
- if((sfname=tempnam("\\temp","SORT"))==NULL) return(SORTERR);
- strcpy(sortfile,sfname);
- free(sfname);
-
- sfh = open(sortfile,
- O_RDWR | O_BINARY | O_DENYNONE | O_CREAT | O_TRUNC,
- S_IREAD | S_IWRITE); /* Get file Handle */
- if(sfh == -1) return(SORTERR);
-
- sbfflag = TRUE; /* Sort File is now Open */
- sbfptr = 0;
- }
- qsort(sbuf, (size_t) bufcount, (size_t) tagsize, stricmp);
- lseek(sfh, sbfptr, 0); /* Seek to position */
- sorterror = 3;
- if(write (sfh, sbuf,sbsize) != sbsize) return(SORTERR);
- sblocks++;
- sbfptr += sbsize; /* Move the File Pointer */
- zerobuf(sbuf, sbsize); /* Zero the Sort Buffer */
- return(SORTOK);
- }
-
- /** =============================================================
-
- The merge step passes
- BACK POINTERS DIRECTLY FROM THE MERGE FUNCTION. I.E. 20 BUCKETS FROM 20
- BLOCKS ARE HELD IN MEMORY AND KEEP BEING REFILLED.
-
-
- SBLOCKS are written to disk as 'sbsize' records. Merge has pointers to each
- block. When a block's pointer reaches the next block's start point it has
- exhausted that block.
- bptr[1] == bptr[2] = Block Exhausted
- (*bptr[1] == -1) = No more records here
-
- ALL DATA SORTED (SORT TAGS) ARE ALWAYS CHARACTER.
- This means that -1 for a sort tag means end of tags this block.
-
-
- ** ================================================================**/
-
- /************************************************************************
- * MERGE - Merge the sorted.
- * If only 1 sort block no need to write to a file. Sort it in memory.
- ***********************************************************************/
- merge()
- {
-
- unsigned bktarea;
- int i, cbucket; /* ChosenBucket # */
- char *ctag; /* Chosen Tag */
- long rpos; /* Record Position Value */
- char *sfname;
-
-
- stptr = sbuf; /* Be sure the pointer is pointed to the Sort Buf for Fetch */
-
- /*
- * For The First scenario there is only the sortblock still in
- * memory. All we have to do is sort it and ready for the Fetch.
- */
- if(sblocks == 0)
- {
- qsort(sbuf,(size_t) bufcount,(size_t) staglen + sizeof(long), stricmp);
- bufcount = 0;
- if(initfetch()==SORTERR) return(SORTERR);
- return(SORTOK);
- }
-
- /*
- * Open the Merge File Now
- */
- sorterror = 4;
- if((sfname=tempnam("\\temp","MERGE"))==NULL) return(SORTERR);
- strcpy(mergefile,sfname);
- free(sfname);
-
- mfh = open(mergefile,
- O_RDWR | O_BINARY | O_DENYNONE | O_CREAT | O_TRUNC,
- S_IREAD | S_IWRITE); /* Get file Handle */
- if(mfh == -1) return(SORTERR);
-
-
- /*
- * Scenario TWO says there have been 1 or more blocks written to disk.
- * Now we must merge the blocks to be ready to fetch. If there's data
- * in the sort buffer write it out. Then split the sort buffer into two
- * sections.
- * Section 1 = MergeBuckets (sbuf=the start mbktptr=the pointer)
- * Section 2 = MergeBuffer (mrgbuf=the start mbptr=the pointer)
- */
-
- if(bufcount)
- {
- if(sbwrite()==SORTERR) return(SORTERR);
- }
- zerobuf(sbuf, sbsize); /* Zero the whole buffer */
- buckets = sblocks; /* The number of merge buckets needed */
- bktsize = tagsize + mcountsize; /* Size of the bucket in total */
- bktarea = bktsize * buckets; /* Size of the buckets area */
- mbsize = sbsize - bktarea; /* What's left is merge buffer */
- mbufmax = mbsize / tagsize; /* Number to fit in merge buffer */
- mrgbuf = sbuf + bktarea; /* Pointing to merge buffer */
- mbptr = mrgbuf;
- bufcount = 0; /* Zero the counter */
- sorterror = 5;
- if(mbufmax < 1) return(SORTERR);
- /*
- * Now fill in the initial buckets. The Bucket format is as follows:
- * SortBlockCount(BUFMAX) - file pointer - TAG - Tag pointer
- */
- for(i=0; i<buckets; i++)
- {
- bktptr = sbuf + (i * bktsize); /* Point to the bucket */
- uptr = (unsigned *) bktptr; /* Ready to accept an unsigned value */
- *uptr = 0; /* counter of the Sort Block */
- if(bktfill(i)==SORTERR) return(SORTERR); /* Fill in the bucket while we're here */
- }
-
- /*
- * Now all buckets are set up and the first element should be in each bucket.
- * The next step is to Find the lowest element and move it to the buffer.
- * When an element is moved to the buffer it will also be replaced in the
- * bucket. When the merge buffer fills it will be written to disk to the
- * final sorted file.
- */
- while(TRUE)
- {
- cbucket = -1; /* Clear the Selection */
- ctag = NULL; /* Null the pointer */
-
- for(i=0; i<buckets; i++)
- {
- bktptr = sbuf + (i * bktsize); /* Point to the bucket */
- uptr = (unsigned *) bktptr; /* Ready to accept an unsigned value */
- bktptr += mcountsize; /* Point it at TAG */
-
- /* Skip bucket if depleted or No more tags here */
- if(*uptr < bufmax+1 && bktptr[0] != -1)
- {
- if(ctag==NULL) ctag = bktptr; /* Starting point for compare */
- if(stricmp(ctag, bktptr)>=0)
- {
- ctag = bktptr; /* New Lower value */
- cbucket = i;
- }
- }
- }
- if(cbucket < 0) break; /* No more tags We're DONE !! */
-
- /*
- * We have the lowest tag pointed to by ctag. Move it to the buffer
- */
- strcpy(mbptr, ctag); /* Copy the tag in */
- ctag += staglen; /* Move to the record pointer value */
- mbptr += staglen; /* Ditto in the merge buffer */
-
- lptr = (long *) ctag; /* Point at record position */
- rpos = *lptr; /* And get the value */
-
- lptr = (long *) mbptr; /* Ready to get long value */
- *lptr = rpos; /* Get record pointer */
- mbptr +=tpsize; /* Point to next tag area */
-
- if(bktfill(cbucket)==SORTERR) return(SORTERR);
- bufcount++;
- if(bufcount >= mbufmax)
- {
- mbwrite(bufcount); /* Write out the merge buffer */
- mbptr = mrgbuf; /* Reset the pointer */
- bufcount = 0;
- }
- }
-
- mbwrite(bufcount); /* The final Write and we're done */
- if(initfetch()==SORTERR) return(SORTERR);
- return(SORTOK);
- }
-
- /***********************************************************************
- * MBWRITE - Write out a MERGE buffer full of tags
- * Tags are written to the final sorted file.
- *
- ***********************************************************************/
- mbwrite(unsigned tagcount)
- {
- unsigned wsize;
-
- sorterror = 7;
- wsize = tagsize * tagcount;
- if(write(mfh, mrgbuf,wsize) != wsize) return(SORTERR);
- zerobuf(mrgbuf, mbsize); /* Zero the Merge Buffer */
- return(SORTOK);
- }
-
- /***********************************************************************
- * BKTFILL - Fill in a sort buckt from the Sort Blocks file
- ***********************************************************************/
- bktfill(int bnum)
- {
- char *bptr; /* pointer to bucket */
- long *bktlptr; /* Bucket long pointer */
- long sbfpos; /* sort block file position */
-
- bptr = sbuf + (bnum * bktsize); /* Point to the bucket */
-
- uptr = (unsigned *) bptr;
- if(*uptr > bufmax) return(SORTOK); /* Nothing to get, this block is depleted */
-
- bptr += mcountsize; /* Move block pointer to merge tag */
-
- sbfpos = (bnum * sbsize) + (tagsize * *uptr); /* Calc file position */
-
- sorterror = 6;
- if(lseek(sfh, sbfpos, 0)== -1l) return(SORTERR);
- if(read(sfh, (void *)bptr, (unsigned)tagsize) != (unsigned)tagsize) return(SORTERR);
-
- ++*uptr; /* Increment the counter */
- return(SORTOK);
- }
- /*********************************************************************
- * ZEROBUF - Fill a buffer with FF (-1)
- *********************************************************************/
- zerobuf(char *bptr, unsigned count)
- {
-
- memset(bptr, -1, count);
- }